/**
 * データベース(MySQL)にアクセスし、結果を取得するクラス
 *
 */
package wildcard.database;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;

public class DBAccess {
	public static final String SQL_SELECT_COMMAND = "SELECT COMMAND FROM SQL_COMMANDS WHERE ID = ?";
	public static final String SQL_UPDATE_GENERAL = "UPDATE ? SET ? = ? WHERE ID = ?; ";
	public static final String SQL_UPDATE_ERASE = "UPDATE ? SET UNAPPLIED = NOW() WHERE ID = ?; ";

	/**
	 * SQLの実行を行い、結果をHashMapでレコードを表現したArrayListで返す。
	 * HashMapは得られた結果のメタデータに格納されているカラム名がキー値となる。 なお、nullは返さず、その場合、空リストのを返す。
	 *
	 * @param データベースユーザID
	 * @param データベースユーザパスワード
	 * @param SQL文
	 * @param 外部入力されたSQL用パラメータ
	 * @return SQLによって得られた、カラム名をキー値としたレコードのリスト
	 */
	public final static ArrayList<ArrayList<String>> executeSelect(
			final String dbId, final String dbPassword, final String sql,
			ArrayList<String> parameters) {

		// 戻り値となるArrayList
		ArrayList<ArrayList<String>> resultList = new ArrayList<ArrayList<String>>(
				0);

		Connection con = null;
		PreparedStatement statement = null;

		try {
			// データベース接続
			con = DBManager.getConnection(dbId, dbPassword);
			statement = DBAccess.setStatementParameter(
					con.prepareStatement(sql), parameters);

			// SQLの実行
			ResultSet resultSet = statement.executeQuery();

			resultList = createResult(resultSet);

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				// データベースはその場で開放する
				if (con != null) {
					con.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		return resultList;
	}

	private static ArrayList<ArrayList<String>> createResult(ResultSet resultSet)
			throws SQLException {
		ArrayList<ArrayList<String>> resultList = new ArrayList<ArrayList<String>>();
		;

		// メタデータの取得
		ResultSetMetaData meta = resultSet.getMetaData();

		// メタデータを使い、カラム名を取得する
		ArrayList<String> metaList = new ArrayList<String>();
		for (int i = 0; i < meta.getColumnCount(); i++) {
			metaList.add(meta.getColumnLabel(i + 1));
			System.out.print(meta.getColumnLabel(i + 1) + " ");
		}
		System.out.println();

		// 全レコードを格納するまで戻り値用リストに追加を繰り返す
		resultList.add(metaList);

		while (resultSet.next()) {
			// 一度レコードをArrayListに格納する
			ArrayList<String> record = new ArrayList<String>();
			for (int i = 0; i < meta.getColumnCount(); i++) {
				record.add(resultSet.getString(i + 1));
				System.out.print(resultSet.getString(i + 1) + " ");
			}
			System.out.println();
			resultList.add(record);
		}

		return resultList;
	}

	public final static int executeUpdate(final String dbId,
			final String dbPassword, final String sql,
			ArrayList<String> parameters) {
		Connection con = null;
		PreparedStatement statement = null;

		// 戻り値となる実行結果(0の場合何も起こっていないことを示す)
		int result = 0;

		try {
			// データベース接続
			con = DBManager.getConnection(dbId, dbPassword);
			statement = DBAccess.setStatementParameter(
					con.prepareStatement(sql), parameters);

			// SQLの実行
			result = statement.executeUpdate();

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				// データベースはその場で開放する
				if (con != null) {
					con.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		return result;
	}

	/**
	 * 設定したSQL文にパラメータを格納する。 変更が起こらないよう、オーバーライドは禁止している。
	 *
	 * @param statement
	 * @param parameters
	 * @return 最終的に実行するSQL文を設定したPreparedStatement
	 * @throws SQLException
	 */
	private final static PreparedStatement setStatementParameter(
			PreparedStatement statement, ArrayList<String> parameters)
			throws SQLException {
		if (parameters == null || parameters.isEmpty()) {
			return statement;
		}else {
			for (int i = 0; i < parameters.size(); i++) {
				statement.setString(i + 1, parameters.get(i));
			}
		}

		return statement;
	}
}
